CloudFrontのアクセスログをS3シンボリックリンクを利用してAthanaで効率的に解析してみた。(Lambdaレス版)
CloudFront のアクセスログを S3への保存する設定のみを実施していた環境で、 直近のアクセスログを対象とした、ログ解析を行う必要がありました。
Athenaによるフルスキャンにより発生する S3、Athena費用を抑制するため、 CloudShellを利用して、調査対象のアクセスログを反映したシンボリックファイルを用意。 Athenaのパーティション投影に対応した形式でS3に設置し、解析する機会がありましたので紹介させて頂きます。
S3にフラットに配置してしまったログも大丈夫!シンボリックリンクを利用してスキャン範囲を絞ってAthenaからクエリする
手順
CloudShell
- CloudFrontのアクセスログ保管S3バケットのファイルリストより、過去一週間の日付に一致するファイルを抽出しました。
- シンボリックファイル保存用のS3バケット、日付「YYYY/MM/DD」を含む状態で保存しました。
S3BUCKET='<ログ保管S3バケット>' S3SYMLINK='<シンボリックファイル保管S3バケット>' TMPDIR="/tmp/$?" mkdir -p ${TMPDIR} cd ${TMPDIR} aws s3 ls s3://${S3BUCKET} --recursive | sed "s/^.* /s3:\/\/${S3BUCKET}\//g" > s3ls.txt for i in {0..6} do mkdir -p "${TMPDIR}/`date +%Y/%m/%d --date \"${i} day ago\"`" SYMLINKFILE="${TMPDIR}/`date +%Y/%m/%d --date \"${i} day ago\"`/symlink.txt" tmp=`date +%Y-%m-%d --date "${i} day ago"` cat s3ls.txt | grep -e "${tmp}-[0-9].\..*.gz$" > ${SYMLINKFILE} done aws s3 sync ${TMPDIR} s3://${S3SYMLINK} --exclude '*' --include '2[0-9][0-9][0-9]/*/symlink.txt'
- ログ出力先のS3バケット、複数のディストリビューションで共有している場合、
aws s3 ls <bucket> --recursive
のS3パス指定を調整してご利用ください。 - アクセスログのファイル数が多く CloudShellではメモリ不足となる場合には、メモリを多く搭載したEC2などの実行環境をご利用ください。
Athena
テーブル作成
INPUTFORMATとして「SymlinkTextInputFormat」。 LOCATION、TBLPROPERTIES は、シンボリックファイル保存先のS3バケットとしたテーブルを作成しました。
CREATE EXTERNAL TABLE IF NOT EXISTS cflogs_parted ( `date` DATE, time STRING, location STRING, bytes BIGINT, requestip STRING, method STRING, host STRING, uri STRING, status INT, referrer STRING, useragent STRING, querystring STRING, cookie STRING, resulttype STRING, requestid STRING, hostheader STRING, requestprotocol STRING, requestbytes BIGINT, timetaken FLOAT, xforwardedfor STRING, sslprotocol STRING, sslcipher STRING, responseresulttype STRING, httpversion STRING, filestatus STRING, encryptedfields INT ) PARTITIONED BY (day STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.SymlinkTextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.IgnoreKeyTextOutputFormat' LOCATION 's3://<シンボリックファイル保管S3バケット>/' TBLPROPERTIES ( 'skip.header.line.count'='2', "projection.enabled" = "true", "projection.day.type" = "date", "projection.day.range" = "2022/01/01,NOW", "projection.day.format" = "yyyy/MM/dd", "projection.day.interval" = "1", "projection.day.interval.unit" = "DAYS", "storage.location.template" = "s3://<シンボリックファイル保管S3バケット>/${day}" )
クエリサンプル
スキャン範囲をパーティション「day」に限定したクエリ結果が得られました。
まとめ
CloudFront の標準アクセスログ、ファイル名にログ生成日時が含まれますが、 Athena のパーティション、パーティション投影で利用できる形式ではないため、Athenaを利用したログ解析時のフルスキャンを避けるためには 事前にLambdaなどを利用したリネームを行う必要がありました。
CloudFront が Amazon S3 バケットに保存する各ログファイルの名前には、次のファイル名形式が使用されます。
/ .YYYY-MM-DD-HH.unique-ID.gz
CloudFront のアクセスログ解析を稀に実施する必要があるが、 フルスキャンに伴う S3、Athenaのコスト抑制が望ましい、 Lambdaなど 管理するAWSリソースを増やしたくない場合、準備が容易な今回の手順をお試しください。
頻繁にCloudFrontのログ解析の必要がある場合や、アクセスログの長期保管要件のため シンボリックファイルの作成が難しい場合、 従来のアクセスログファイルのりネームを実施するLambda関数や、 要件によっては Glueの活用もご検討ください。
CloudFrontのアクセスログをパーティション射影を使ってコスパ良くAthenaでクエリーする仕組みをCDKで作った